using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using AlgLrnLib.Searching;

namespace AlgLrn
{
    public partial class frmSearch : Form
    {
        #region Private Fields
        private int _traceIndex;
        #endregion

        #region Constructor
        public frmSearch()
        {
            InitializeComponent();
        }
        #endregion

        #region Event Handlers
        private void frmSearch_Load(object sender, EventArgs e)
        {
            cbbxSearchType.SelectedIndex = 0;
        }

        private void frmSearch_ResizeEnd(object sender, EventArgs e)
        {
            if (this.Width < Constants.MinFormWidth)
                this.Width = Constants.MinFormWidth;

            if (this.Height < Constants.MinFormHeight)
                this.Height = Constants.MinFormHeight;
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            string strNumbers = txtInput.Text.Trim();
            string strSearchVal = txtSearchVal.Text.Trim();

            if (string.IsNullOrEmpty(strNumbers) || string.IsNullOrEmpty(strSearchVal))
                return;

            int[] numbers = PrepareNumbers(strNumbers);
            if (numbers == null)
                return;

            int searchVal;
            bool parsed = Int32.TryParse(strSearchVal, out searchVal);
            if (!parsed)
                return;

            SearchThreadData td = new SearchThreadData(numbers, cbbxSearchType.SelectedIndex, searchVal);
            ClearOutput();
            bwSearchThread.RunWorkerAsync(td);

            ResetGUI();
        }

        private void bwSearchThread_DoWork(object sender, DoWorkEventArgs e)
        {
            SearchThreadData td = (SearchThreadData)e.Argument;
            td.Index = Search(td);
            e.Result = td;
        }

        private void bwSearchThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            string traceinfo = (string)e.UserState;
            txtItterations.Text += traceinfo + "\r\n";
        }

        private void bwSearchThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            SearchThreadData td = (SearchThreadData)e.Result;
            wbResults.DocumentText = BuildOutput(td.Numbers, td.Index);
            ResetGUI();
        }
        #endregion

        #region Private Members
        private int[] PrepareNumbers(string numbers)
        {
            string[] numbersStrArr = numbers.Split(',');
            int[] numbersArr = new int[numbersStrArr.Length];
            int i = 0;
            foreach (string number in numbersStrArr)
            {
                int nNumber;
                if (!Int32.TryParse(number, out nNumber))
                    return null;

                numbersArr[i] = nNumber;
                i++;
            }

            return numbersArr;
        }

        private int Search(SearchThreadData td)
        {
            int retVal = -1;
            BaseSearch srch = null;

            switch (td.SearchType)
            {
                case Constants.LinearSearch:
                    srch = new LinearSearch();
                    retVal = srch.FindIndex(td.Numbers, td.SearchingValue, DebugTrace);
                    break;
                case Constants.BinarySearch:
                    srch = new BinarySearch();
                    retVal = srch.FindIndex(td.Numbers, td.SearchingValue, DebugTrace);
                    break;
                default:
                    break;
            }

            return retVal;
        }

        private void ClearOutput()
        {
            txtItterations.Text = string.Empty;
            wbResults.DocumentText = string.Empty;
        }

        private void ResetGUI()
        {
            btnSearch.Enabled = !bwSearchThread.IsBusy && cbbxSearchType.SelectedIndex > -1;
        }

        private void DebugTrace(int[] numbers, string notes, bool withClear)
        {
            if (!cbbxDumpSteps.Checked)
            {
                ClearOutput();
                return;
            }

            if (withClear)
            {
                ClearOutput();
                _traceIndex = 0;
            }

            _traceIndex++;

            StringBuilder sbldNumber = new StringBuilder();

            foreach (double number in numbers)
                sbldNumber.Append(string.Format("{0},", number));

            string strNumber = sbldNumber.ToString();
            strNumber = strNumber.Substring(0, strNumber.Length - 2);

            if (!string.IsNullOrEmpty(notes))
                strNumber = string.Format("{0:d4}. {1} -> {2}", _traceIndex, strNumber, notes);

            if (bwSearchThread != null && bwSearchThread.IsBusy && !bwSearchThread.CancellationPending)
                bwSearchThread.ReportProgress(0, strNumber);
        }

        //wbResults.DocumentText = "<html><body>S<font color=\"red\">A</font>MPLE</body></html>";
        private string BuildOutput(int[] numbers, int index)
        {
            if (index == -1) // item was not found
                return "<html><body><font color=\"red\">Item was not found!</font></body></html>";

            if (index >= numbers.Length)
                return "<html><body><font color=\"red\">Index out of bounds!</font></body></html>";

            string retVal = "<html><body>";
            for (int i = 0; i < numbers.Length; i++)
                if (i == index)
                    retVal += string.Format("<font color=\"red\">&nbsp{0}</font>", numbers[i]);
                else
                    retVal += string.Format("&nbsp{0}", numbers[i]);

            return string.Format("{0}</body></html>", retVal);
        }
        #endregion
    }
}
